// MemStream.cpp: implementation of the CMemStream class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include <pgl/algotools/MemStream.h>

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

namespace algotools
{

CHGlobalWrapper::~CHGlobalWrapper()		
{	
	ClearHandle();
	ClearSafeArray();
};

CHGlobalWrapper::CHGlobalWrapper()
: m_bLocked(false), m_hGlobal(NULL), m_pSafeArray(NULL),
m_bSAUpdated(false)
{
	m_hGlobal=::GlobalAlloc( GHND, 0);
	
	VariantInit(&m_var);
	m_var.vt=VT_ARRAY | VT_UI1;
};

void CHGlobalWrapper::ClearHandle()
{
	if (m_hGlobal)
	{
		if (m_bLocked)
			::GlobalUnlock(m_hGlobal);
				
		::GlobalFree(m_hGlobal);
		m_hGlobal=NULL;
	}
}

void CHGlobalWrapper::ClearSafeArray()
{
	if (m_pSafeArray)
	{
		::SafeArrayDestroy( m_pSafeArray );
		m_pSafeArray=NULL;
	}
	m_bSAUpdated=false;
}	

void CHGlobalWrapper::UpdateSafeArray()
{
	if (!IsValid() || m_bSAUpdated)
		return;

	size_t size=Size();
	LPVOID pSrcData = Lock();
	if (pSrcData)
	{
		ClearSafeArray();

		m_pSafeArray=::SafeArrayCreateVector(
			VT_UI1,
			0,
			Size());

		if (m_pSafeArray)
		{
			HRESULT hr;
			LPVOID pArrayData(NULL);
		
			hr = ::SafeArrayAccessData( 
					m_pSafeArray,
					&pArrayData);
		
			if (pArrayData)
			{
				memcpy( pArrayData, pSrcData, size);
					
				::SafeArrayUnaccessData(m_pSafeArray);
			}
		}

		UnLock();
	}

	m_var.parray=ToSafeArray();

	m_bSAUpdated=true;
}

SAFEARRAY* CHGlobalWrapper::ToSafeArray()
{
	UpdateSafeArray();
	return m_pSafeArray;
}

const VARIANT& CHGlobalWrapper::ToVariant()
{
	UpdateSafeArray();
	return m_var;
}

LPVOID CHGlobalWrapper::LockToLPVOID()
{
	ClearSafeArray();
	return Lock();
}

LPVOID CHGlobalWrapper::Lock()	
{
    if (m_bLocked)
        throw std::exception("HGlobal already locked");
	m_bLocked=true;

	return ::GlobalLock(m_hGlobal);
}

void CHGlobalWrapper::UnLock()
{	
    if (!m_bLocked)
        throw std::exception("HGlobal not locked, cannot unlock");
	m_bLocked=false;

	::GlobalUnlock(m_hGlobal);
}

CMemStream::CMemStream( )
: m_pStream(NULL), m_hResult(S_FALSE)
{
	if (CHGlobalWrapper::IsValid())
	{
		m_hResult=::CreateStreamOnHGlobal(
			ToHandle(),         //Memory handle for the stream object
			true,   //Whether to free memory when the 
			// object is released
			&m_pStream          //Address of output variable that 
			// receives the IStream interface pointer
			);
	}
}


void CMemStream::ClearStream()
{
	if (m_pStream)
	{
		m_pStream->Release();
		m_pStream=NULL;
	}
}			

};